home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 26 / AMIGAplus Sonderheft 26 (2000)(Falke)(DE)(Track 1 of 2)[!].iso / Tools / Packer / PPCUnACE / Src / unace.c < prev    next >
C/C++ Source or Header  |  1999-03-29  |  18KB  |  637 lines

  1. /* ------------------------------------------------------------------------ */
  2. /*                                                                          */
  3. /*      Main file of public UNACE.                                          */
  4. /*                                                                          */
  5. /* ------------------------------------------------------------------------ */
  6.  
  7.  
  8. //--------------- include general files ------------------------------------//
  9. #include <ctype.h>      // tolower()
  10. #include <fcntl.h>      // open()
  11. #include <stdio.h>      // printf() sprintf() remove()
  12. #include <stdlib.h>     // malloc()
  13. #include <string.h>     // str*()
  14. #include <sys/stat.h>   // S_I*  AMIGA: fstat()
  15.  
  16.  
  17. #if defined(AMIGA)
  18.  #include <error.h>     // errno
  19.  #include <proto/dos.h>
  20. #endif
  21. #if defined(DOS) || defined(WINNT) || defined(WIN16) || defined(OS2)
  22.  #include <io.h>        // lseek() open() read() write() eof() close()
  23. #endif
  24. #if defined(DOS) || defined(WINNT) || defined(WIN16)
  25.  #include <dos.h>       // lseek() open() read() write() eof() close()
  26. #endif
  27. #if defined(UNIX)
  28.  #include <unistd.h>
  29.  #include <errno.h>
  30. #endif
  31.  
  32. //--------------- include unace specific header files ----------------------//
  33. #include "os.h"
  34.  
  35. #include "globals.h"
  36. #include "portable.h"
  37. #include "uac_comm.h"
  38. #include "uac_crc.h"
  39. #include "uac_crt.h"
  40. #include "uac_dcpr.h"
  41. #include "uac_sys.h"
  42.  
  43. //--------------- BEGIN OF UNACE ROUTINES ----------------------------------//
  44.  
  45. #ifdef CASEINSENSE
  46.  
  47. #include <ctype.h>
  48.  
  49. /* fileexists() hack:
  50.  * if first try of file existing doesn't work then swap Case of the c
  51.  * in the .CXX extension
  52.  */
  53. INT fileexists_insense(char *name)
  54. {
  55.   int len;
  56.   char *s;
  57.  
  58.   if (fileexists(name))
  59.     return 1;
  60.  
  61.   len = strlen(name);
  62.   if (len >= 3)
  63.   {
  64.     s = &name[len-3];
  65.     if (isalpha(*s))
  66.     {
  67.       if (islower(*s))
  68.         *s = toupper(*s);
  69.       else
  70.         *s = tolower(*s);
  71.       return fileexists(name);
  72.     }
  73.   }
  74.   return 0;
  75. }
  76.  
  77. #else
  78.   #define fileexists_insense(name) fileexists(name)
  79. #endif
  80.  
  81.  
  82. void init_unace(void)           // initializes unace
  83. {
  84.    buf_rd =malloc(size_rdb * sizeof(ULONG));  // Allocate buffers: increase
  85.    buf    =malloc(size_buf);                  // sizes when possible to speed
  86.    buf_wr =malloc(size_wrb);                  // up the program
  87.    readbuf=malloc(size_headrdb);
  88.  
  89.    if (buf_rd ==NULL ||
  90.        buf    ==NULL ||
  91.        buf_wr ==NULL ||
  92.        readbuf==NULL )
  93.       f_err = ERR_MEM;
  94.  
  95.    make_crctable();             // initialize CRC table
  96.    dcpr_init();                 // initialize decompression
  97.  
  98.    set_handler();               // ctrl+break etc.
  99. }
  100.  
  101. void done_unace(void)
  102. {
  103.    if (buf_rd   ) free(buf_rd   );
  104.    if (buf      ) free(buf      );
  105.    if (buf_wr   ) free(buf_wr   );
  106.    if (readbuf  ) free(readbuf  );
  107.    if (dcpr_text) free(dcpr_text);
  108. }
  109.  
  110. INT  read_header(INT print_err)         // reads any header from archive
  111. {
  112.    USHORT rd,
  113.         head_size,
  114.         crc_ok;
  115.    LONG crc;
  116.    UCHAR *tp=readbuf;
  117.  
  118.    lseek(archan, skipsize, SEEK_CUR);   // skip ADDSIZE block
  119.  
  120.    if (read(archan, &head, 4)<4)
  121.       return 0;                         // read CRC and header size
  122.  
  123. #ifdef HI_LO_BYTE_ORDER
  124.    WORDswap(&head.HEAD_CRC);
  125.    WORDswap(&head.HEAD_SIZE);
  126. #endif
  127.                                         // read size_headrdb bytes into 
  128.    head_size = head.HEAD_SIZE;          // header structure 
  129.    rd = (head_size > size_headrdb) ? size_headrdb : head_size;
  130.    if (read(archan, readbuf, rd) < rd)
  131.       return 0;
  132.    head_size -= rd;
  133.    crc = getcrc(CRC_MASK, readbuf, rd);
  134.  
  135.    while (head_size)                    // skip rest of header
  136.    {                            
  137.       rd = (head_size > size_buf) ? size_buf : head_size;
  138.       if (read(archan, buf, rd) < rd)
  139.          return 0;
  140.       head_size -= rd;
  141.       crc = getcrc(crc, buf, rd);
  142.    }
  143.  
  144.    head.HEAD_TYPE =*tp++;               // generic buffer to head conversion
  145.    head.HEAD_FLAGS=BUFP2WORD(tp);
  146.  
  147.    if (head.HEAD_FLAGS & ACE_ADDSIZE)
  148.       skipsize = head.ADDSIZE = BUF2LONG(tp);   // get ADDSIZE
  149.    else
  150.       skipsize = 0;
  151.  
  152.                                                 // check header CRC 
  153.    if (!(crc_ok = head.HEAD_CRC == (crc & 0xffff)) && print_err)
  154.       printf("\nError: archive is broken\n");
  155.    else
  156.    switch (head.HEAD_TYPE)              // specific buffer to head conversion
  157.    {
  158.       case MAIN_BLK:
  159.          memcpy(mhead.ACESIGN, tp, acesign_len); tp+=acesign_len;
  160.          mhead.VER_MOD=*tp++;
  161.          mhead.VER_CR =*tp++;
  162.          mhead.HOST_CR=*tp++;
  163.          mhead.VOL_NUM=*tp++;
  164.          mhead.TIME_CR=BUFP2LONG(tp);
  165.          mhead.RES1   =BUFP2WORD(tp);
  166.          mhead.RES2   =BUFP2WORD(tp);
  167.          mhead.RES    =BUFP2LONG(tp);
  168.          mhead.AV_SIZE=*tp++;
  169.          memcpy(mhead.AV, tp, rd-(USHORT)(tp-readbuf));
  170.          break;
  171.       case FILE_BLK:
  172.          fhead.PSIZE     =BUFP2LONG(tp);
  173.          fhead.SIZE      =BUFP2LONG(tp);
  174.          fhead.FTIME     =BUFP2LONG(tp);
  175.          fhead.ATTR      =BUFP2LONG(tp);
  176.          fhead.CRC32     =BUFP2LONG(tp);
  177.          fhead.TECH.TYPE =*tp++;
  178.          fhead.TECH.QUAL =*tp++;
  179.          fhead.TECH.PARM =BUFP2WORD(tp);
  180.          fhead.RESERVED  =BUFP2WORD(tp);
  181.          fhead.FNAME_SIZE=BUFP2WORD(tp);
  182.          memcpy(fhead.FNAME, tp, rd-(USHORT)(tp-readbuf));
  183.          break;
  184. //    default: (REC_BLK and future things): 
  185. //              do nothing 'cause isn't needed for extraction
  186.    }
  187.  
  188.    return crc_ok;
  189. }
  190.                                 // maximum SFX module size 
  191. #define max_sfx_size 65536      // (needed by read_arc_head)
  192.  
  193. INT read_arc_head(void)         // searches for the archive header and reads it
  194. {
  195.    INT  i,
  196.         flags,
  197.         buf_pos = 0;
  198.    LONG arc_head_pos,
  199.         old_fpos,
  200.         fpos = 0;
  201.    struct stat st;
  202.  
  203.    fstat(archan, &st);
  204.  
  205.    memset(buf, 0, size_buf);
  206.  
  207.    while (lseek(archan, 0, SEEK_CUR)<st.st_size && fpos < max_sfx_size)
  208.    {
  209.       old_fpos = fpos;
  210.       fpos += read(archan, &buf[buf_pos], size_buf - buf_pos);
  211.  
  212.       for (i = 0; i < size_buf; i++)    // look for the acesign
  213.       {                         
  214.          if (!memcmp(acesign, &buf[i], acesign_len))
  215.          {             
  216.                                         // seek to the probable begin 
  217.                                         // of the archive
  218.             arc_head_pos = old_fpos + i - buf_pos -  bytes_before_acesign;
  219.             lseek(archan, arc_head_pos, SEEK_SET);
  220.             if (read_header(0))         // try to read archive header
  221.             {                           
  222.                flags = mhead.HEAD_FLAGS;
  223.                adat.sol     = (flags & ACE_SOLID) > 0;
  224.                adat.vol     = (flags & ACE_MULT_VOL) > 0;
  225.                adat.vol_num = mhead.VOL_NUM;
  226.                adat.time_cr = mhead.TIME_CR;
  227.                return 1;
  228.             }
  229.          }
  230.       }
  231.                                         // was no archive header,
  232.                                         // continue search
  233.       lseek(archan, fpos, SEEK_SET);
  234.       memcpy(buf, &buf[size_buf - 512], 512);
  235.       buf_pos = 512;                    // keep 512 old bytes
  236.    }
  237.    return 0;
  238. }
  239.  
  240. INT  open_archive(INT print_err)        // opens archive (or volume)
  241. {
  242.    CHAR av_str[80];
  243.  
  244.    archan = open(aname, O_RDONLY | O_BINARY);   // open file
  245.  
  246.    if (archan == -1)
  247.    {
  248.       printf("\nError opening file %s", aname);
  249.       return 0;
  250.    }
  251.    if (!read_arc_head())                        // read archive header
  252.    {                            
  253.       if (print_err)
  254.          printf("\nInvalid archive file: %s\n", aname);
  255.       close(archan);
  256.       return 0;
  257.    }
  258.  
  259.    printf("\nProcessing archive: %s\n\n", aname);
  260.    if (head.HEAD_FLAGS & ACE_AV)
  261.    {
  262.       printf("Authenticity Verification:");   // print the AV
  263.       sprintf(av_str, "\ncreated on %d.%d.%d by ",
  264.               ts_day(adat.time_cr), ts_month(adat.time_cr), ts_year(adat.time_cr));
  265.       printf(av_str);
  266.       strncpy(av_str, mhead.AV, mhead.AV_SIZE);
  267.       av_str[mhead.AV_SIZE] = 0;
  268.       printf("%s\n\n", av_str);
  269.    }
  270.    comment_out("Main comment:");        // print main comment
  271.    return 1;
  272. }
  273.  
  274. void get_next_volname(void)             // get file name of next volume
  275. {
  276.    CHAR *cp;
  277.    INT  num;
  278.  
  279.    if ((cp = (CHAR *) strrchr(aname, '.')) == NULL || !*(cp + 1))
  280.       num = -1;
  281.    else
  282.    {
  283.       cp++;
  284.       num = (*(cp + 1) - '0') * 10 + *(cp + 2) - '0';
  285.       if (!in(num, 0, 99))
  286.          num = -1;
  287.       if (in(*cp, '0', '9'))
  288.          num += (*cp - '0') * 100;
  289.    }
  290.    num++;
  291.  
  292.    if (num < 100)
  293.       *cp = 'C';
  294.    else
  295.       *cp = num / 100 + '0';
  296.    *(cp + 1) = (num / 10) % 10 + '0';
  297.    *(cp + 2) = num % 10 + '0';
  298. }
  299.  
  300. INT  proc_vol(void)                     // opens volume
  301. {
  302.    INT  i;
  303.    CHAR s[80];
  304.  
  305.    // if f_allvol_pr is 2 we have -y and should never ask
  306.    if ((!fileexists_insense(aname) && f_allvol_pr != 2) || !f_allvol_pr)
  307.    {
  308.       do
  309.       {
  310.          sprintf(s, "Ready to process %s?", aname);
  311.          beep();
  312.          i = wrask(s);                  // ask whether ready or not
  313.          f_allvol_pr = 0;
  314.          if(i == 1)                     // "Always" --> process all volumes
  315.              f_allvol_pr = 1;
  316.          if (i >= 2)
  317.          {
  318.             f_err = ERR_FOUND;
  319.             return 0;
  320.          }
  321.       }
  322.       while (!fileexists_insense(aname));
  323.    }
  324.  
  325.    if (!open_archive(1))                // open volume
  326.    {                            
  327.       printf("\nError while opening archive. File not found or archive broken.\n");
  328.       f_err = ERR_OPEN;
  329.       return 0;
  330.    }
  331.  
  332.    return 1;
  333. }
  334.  
  335. INT  proc_next_vol(void)        // opens next volume to process
  336. {
  337.    close(archan);               // close handle
  338.    get_next_volname();          // get file name of next volume
  339.  
  340.    if (!proc_vol())             // try to open volume, read archive header
  341.       return 0;
  342.    if (!read_header(1))         // read 2nd header
  343.    {
  344.       f_err=ERR_READ;
  345.       return 0;
  346.    }
  347.    return 1;
  348. }
  349.  
  350. INT  read_adds_blk(CHAR * buffer, INT len)      // reads part of ADD_SIZE block
  351. {
  352.    INT  rd = 0,
  353.         l = len;
  354.    LONG i;
  355.  
  356.    while (!f_err && len && skipsize)
  357.    {
  358.       i = (skipsize > len) ? len : skipsize;
  359.       skipsize -= i;
  360.  
  361.       errno = 0;
  362.       rd += read(archan, buffer, i);
  363.       if (errno)
  364.       {
  365.          printf("\nRead error\n");
  366.          f_err = ERR_READ;
  367.       }
  368.  
  369.       buffer += i;
  370.       len -= i;
  371.  
  372.       if (!skipsize)            // if block is continued on next volume
  373.          if (head.HEAD_FLAGS & ACE_SP_AFTER && !proc_next_vol())
  374.             break;
  375.    }
  376.  
  377.    return (rd > l ? l : rd);
  378. }
  379.  
  380. void crc_print(void)            // checks CRC, prints message
  381. {
  382.    INT  crc_not_ok = rd_crc != fhead.CRC32;  /* check CRC of file */
  383.  
  384.    if(crc_not_ok)
  385.      f_err_crc=1;
  386.  
  387.    if (!f_err)                  // print message
  388.    {                            
  389.       printf(crc_not_ok ? "          CRC-check error" : "          CRC OK");
  390.       flush;
  391.    }
  392. }
  393.  
  394. void analyze_file(void)         // analyzes one file (for solid archives)
  395. {
  396.    printf("\n Analyzing");
  397.    flush;
  398.    while (!cancel() && (dcpr_adds_blk(buf_wr, size_wrb))) // decompress only
  399.       ;
  400.    crc_print();
  401. }
  402.  
  403. void extract_file(void)         // extracts one file
  404. {
  405.    INT  rd;
  406.  
  407.    printf("\n Extracting");
  408.    flush;                       // decompress block
  409.    while (!cancel() && (rd = dcpr_adds_blk(buf_wr, size_wrb)))
  410.    {
  411.       if (write(wrhan, buf_wr, rd) != rd)       // write block
  412.       {                         
  413.          printf("\nWrite error\n");
  414.          f_err = ERR_WRITE;
  415.       }
  416.    }
  417.    crc_print();
  418. }
  419.  
  420. /* extracts or tests all files of the archive
  421.  */
  422. void extract_files(int nopath, int test)
  423. {
  424.    CHAR file[PATH_MAX];
  425.  
  426.    while (!cancel() && read_header(1))
  427.    {
  428.       if (head.HEAD_TYPE == FILE_BLK)
  429.       {
  430.          comment_out("File comment:");   // show file comment
  431.          ace_fname(file, &head, nopath); // get file name
  432.          printf("\n%s", file);
  433.          flush;
  434.          dcpr_init_file();               // initialize decompression of file
  435.          if (!f_err)
  436.          {
  437.             if (test || 
  438.                 (wrhan = create_dest_file(file, (INT) fhead.ATTR))<0)
  439.             {
  440.                if (test || adat.sol)
  441.                   analyze_file();        // analyze file
  442.             }
  443.             else
  444.             {
  445.                extract_file();           // extract it
  446. #ifdef DOS                               // set file time
  447.                _dos_setftime(wrhan, (USHORT) (fhead.FTIME >> 16), (USHORT) fhead.FTIME);
  448. #endif
  449.                close(wrhan);
  450. #ifdef DOS                               // set file attributes
  451.                _dos_setfileattr(file, (UINT) fhead.ATTR);
  452. #endif
  453. #ifdef AMIGA
  454.                {                         // set file date and time
  455.                   struct DateTime dt;
  456.                   char Date[9], Time[9];
  457.                   ULONG tstamp=fhead.FTIME;
  458.  
  459.                   sprintf(Date, "%02d-%02d-%02d", ts_year(tstamp)-1900, ts_month(tstamp), ts_day(tstamp));
  460.                   sprintf(Time, "%02d:%02d:%02d", ts_hour(tstamp), ts_min(tstamp), ts_sec(tstamp));
  461.  
  462.                   dt.dat_Format = FORMAT_INT;
  463.                   dt.dat_Flags  = 0;
  464.                   dt.dat_StrDate= Date;
  465.                   dt.dat_StrTime= Time;
  466.  
  467.                   if (StrToDate(&dt))
  468.                      SetFileDate(file, &dt.dat_Stamp);
  469.                }
  470. #endif
  471.                if (f_err)
  472.                   remove(file);
  473.             }
  474.          }
  475.       }
  476.    }
  477. }
  478.  
  479. unsigned percentage(ULONG p, ULONG d)
  480. {
  481.    return (unsigned)( d ? (d/2+p*100)/d : 100 );
  482. }
  483.  
  484. void list_files(int verbose)
  485. {
  486.    unsigned files=0;
  487.    ULONG    size =0,
  488.             psize=0,
  489.             tpsize;
  490.    CHAR     file[PATH_MAX];
  491.  
  492.    printf("Date    |Time |Packed     |Size     |Ratio|File\n");
  493.  
  494.    while (!cancel() && read_header(1))
  495.    {
  496.       if (head.HEAD_TYPE == FILE_BLK)
  497.       {
  498.          ULONG ti=fhead.FTIME;
  499.          ace_fname(file, &head, verbose ? 0 : 1); // get file name
  500.  
  501.          size  += fhead.SIZE;
  502.          psize +=
  503.          tpsize = fhead.PSIZE;
  504.          files++;
  505.  
  506.          while (head.HEAD_FLAGS & ACE_SP_AFTER)
  507.          {
  508.             skipsize=0;
  509.             if (!proc_next_vol())
  510.                break;
  511.             psize += fhead.PSIZE;
  512.             tpsize+= fhead.PSIZE;
  513.          }
  514.          if (!f_err)
  515.             printf("%02u.%02u.%02u|%02u:%02u|%c%c%9lu|%9lu|%4u%%|%c%s\n",
  516.                    ts_day (ti), ts_month(ti), ts_year(ti)%100,
  517.                    ts_hour(ti), ts_min  (ti),
  518.                    fhead.HEAD_FLAGS & ACE_SP_BEF   ? '<' : ' ',
  519.                    fhead.HEAD_FLAGS & ACE_SP_AFTER ? '>' : ' ',
  520.                    tpsize, fhead.SIZE, percentage(tpsize, fhead.SIZE),
  521.                    fhead.HEAD_FLAGS & ACE_PASSW    ? '*'    : ' ',
  522.                    file
  523.                   );
  524.       }
  525.    }
  526.    if (!f_err)
  527.    {
  528.       printf("\n                 %9lu|%9lu|%4u%%| %u file%s",
  529.              psize,
  530.              size,
  531.              percentage(psize, size),
  532.              files,
  533.              (char*)(files == 1 ? "" : "s")
  534.             );
  535.    }
  536. }
  537.  
  538. void showhelp(void)
  539. {
  540.    printf("\n"
  541.           "Usage: UNACE <command> [<switches>] <archive[.ace]>\n"
  542.           "\n"
  543.           "Where <command> is one of:\n"
  544.           "\n"
  545.           "  e   Extract files\n"
  546.           "  l   List archive\n"
  547.           "  t   Test archive integrity\n"
  548.           "  v   List archive (verbose)\n"
  549.           "  x   Extract files with full path\n"
  550.           "\n"
  551.           "And <switches> is zero or more of:\n"
  552.           "\n"
  553.           " -y   Assume 'yes' on all questions, never ask for input"
  554.         );
  555.    f_err = ERR_CLINE;
  556. }
  557.  
  558. int main(INT argc, CHAR * argv[])              // processes the archive
  559. {
  560.    INT show_help,
  561.        arg_cnt = 1;
  562.  
  563.    printf(version);
  564.    show_help=0;
  565.  
  566.    if (argc < 3 || strlen(argv[1]) > 1 || argv[argc-1][0] == '-')
  567.       show_help=1;
  568.  
  569.    while (!show_help && argv[++arg_cnt][0] == '-')
  570.    {
  571.       switch (tolower(argv[arg_cnt][1]))
  572.       {
  573.          case 'y':
  574.             f_ovrall    = 1;      // Overwrite all
  575.             f_allvol_pr = 2;      // Process all volumes, and never ask
  576.             break;
  577.          default:
  578.             show_help = 1;
  579.             break;
  580.       }
  581.    }
  582.  
  583.    if (show_help)
  584.      showhelp();
  585.    else
  586.    {
  587.       CHAR *s;
  588.  
  589.       init_unace();                              // initialize unace
  590.  
  591.       strcpy(aname, argv[arg_cnt]);              // get archive name
  592.       if (!(s = (CHAR *) strrchr(aname, DIRSEP)))
  593.          s = aname;
  594.       if (!strrchr(s, '.'))
  595.          strcat(aname, ".ACE");
  596.  
  597.       if (open_archive(1))                       // open archive to process
  598.       {
  599.          if (adat.vol_num)
  600.             printf("\nFirst volume of archive required!\n");
  601.          else
  602.             switch (tolower(*argv[1]))
  603.             {
  604.                case 'e': extract_files(1, 0); break;  // extract files without path
  605.                case 'x': extract_files(0, 0); break;  // extract files with path
  606.                case 'l': list_files   (0   ); break;  // list files
  607.                case 'v': list_files   (1   ); break;  // list files verbose
  608.                case 't': extract_files(0, 1); break;  // test archive integrity.
  609.                default : showhelp();                  // Wrong command!
  610.             }
  611.  
  612.          close(archan);
  613.          if (f_err)
  614.          {
  615.             printf("\nError occurred\n");
  616.             if (f_criterr)
  617.                printf("Critical error on drive %c\n", f_criterr);
  618.          }
  619.       }
  620.       else
  621.          f_err = ERR_CLINE;
  622.  
  623.       done_unace();
  624.    }
  625.  
  626.    putchar('\n');
  627.    putc   ('\n', stderr);
  628.  
  629.    if (!f_err && f_err_crc)
  630.    {
  631.       printf("One or more CRC-errors were found.\n");
  632.       f_err = ERR_CRC;
  633.    }
  634.    return f_err;
  635. }
  636.  
  637.